{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "improving_neural_net_performance.ipynb",
      "version": "0.3.2",
      "views": {},
      "default_view": {},
      "provenance": [],
      "collapsed_sections": [
        "jFfc3saSxg6t",
        "FSPZIiYgyh93",
        "GhFtWjQRzD2l",
        "P8BLQ7T71JWd",
        "copyright-notice"
      ]
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "source": [
        "#### Copyright 2017 Google LLC."
      ],
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "copyright-notice"
      }
    },
    {
      "source": [
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": [],
      "cell_type": "code",
      "metadata": {
        "cellView": "both",
        "colab_type": "code",
        "id": "copyright-notice2",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      }
    },
    {
      "metadata": {
        "id": "eV16J6oUY-HN",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        "# Mejora del rendimiento de las redes neuronales"
      ]
    },
    {
      "metadata": {
        "id": "0Rwl1iXIKxkm",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " **Objetivo de aprendizaje:** mejorar el rendimiento de una red neuronal al normalizar los atributos y aplicar diversos algoritmos de optimizaci\u00f3n\n",
        "\n",
        "**NOTA:** Los m\u00e9todos de optimizaci\u00f3n que se describen en este ejercicio no son espec\u00edficos para las redes neuronales; son medios eficaces para mejorar la mayor\u00eda de los tipos de modelos."
      ]
    },
    {
      "metadata": {
        "id": "lBPTONWzKxkn",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ## Preparaci\u00f3n\n",
        "\n",
        "Primero, cargaremos los datos."
      ]
    },
    {
      "metadata": {
        "id": "VtYVuONUKxko",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "from __future__ import print_function\n",
        "\n",
        "import math\n",
        "\n",
        "from IPython import display\n",
        "from matplotlib import cm\n",
        "from matplotlib import gridspec\n",
        "from matplotlib import pyplot as plt\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "from sklearn import metrics\n",
        "import tensorflow as tf\n",
        "from tensorflow.python.data import Dataset\n",
        "\n",
        "tf.logging.set_verbosity(tf.logging.ERROR)\n",
        "pd.options.display.max_rows = 10\n",
        "pd.options.display.float_format = '{:.1f}'.format\n",
        "\n",
        "california_housing_dataframe = pd.read_csv(\"https://download.mlcc.google.com/mledu-datasets/california_housing_train.csv\", sep=\",\")\n",
        "\n",
        "california_housing_dataframe = california_housing_dataframe.reindex(\n",
        "    np.random.permutation(california_housing_dataframe.index))"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "B8qC-jTIKxkr",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def preprocess_features(california_housing_dataframe):\n",
        "  \"\"\"Prepares input features from California housing data set.\n",
        "\n",
        "  Args:\n",
        "    california_housing_dataframe: A Pandas DataFrame expected to contain data\n",
        "      from the California housing data set.\n",
        "  Returns:\n",
        "    A DataFrame that contains the features to be used for the model, including\n",
        "    synthetic features.\n",
        "  \"\"\"\n",
        "  selected_features = california_housing_dataframe[\n",
        "    [\"latitude\",\n",
        "     \"longitude\",\n",
        "     \"housing_median_age\",\n",
        "     \"total_rooms\",\n",
        "     \"total_bedrooms\",\n",
        "     \"population\",\n",
        "     \"households\",\n",
        "     \"median_income\"]]\n",
        "  processed_features = selected_features.copy()\n",
        "  # Create a synthetic feature.\n",
        "  processed_features[\"rooms_per_person\"] = (\n",
        "    california_housing_dataframe[\"total_rooms\"] /\n",
        "    california_housing_dataframe[\"population\"])\n",
        "  return processed_features\n",
        "\n",
        "def preprocess_targets(california_housing_dataframe):\n",
        "  \"\"\"Prepares target features (i.e., labels) from California housing data set.\n",
        "\n",
        "  Args:\n",
        "    california_housing_dataframe: A Pandas DataFrame expected to contain data\n",
        "      from the California housing data set.\n",
        "  Returns:\n",
        "    A DataFrame that contains the target feature.\n",
        "  \"\"\"\n",
        "  output_targets = pd.DataFrame()\n",
        "  # Scale the target to be in units of thousands of dollars.\n",
        "  output_targets[\"median_house_value\"] = (\n",
        "    california_housing_dataframe[\"median_house_value\"] / 1000.0)\n",
        "  return output_targets"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "Ah6LjMIJ2spZ",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "# Choose the first 12000 (out of 17000) examples for training.\n",
        "training_examples = preprocess_features(california_housing_dataframe.head(12000))\n",
        "training_targets = preprocess_targets(california_housing_dataframe.head(12000))\n",
        "\n",
        "# Choose the last 5000 (out of 17000) examples for validation.\n",
        "validation_examples = preprocess_features(california_housing_dataframe.tail(5000))\n",
        "validation_targets = preprocess_targets(california_housing_dataframe.tail(5000))\n",
        "\n",
        "# Double-check that we've done the right thing.\n",
        "print(\"Training examples summary:\")\n",
        "display.display(training_examples.describe())\n",
        "print(\"Validation examples summary:\")\n",
        "display.display(validation_examples.describe())\n",
        "\n",
        "print(\"Training targets summary:\")\n",
        "display.display(training_targets.describe())\n",
        "print(\"Validation targets summary:\")\n",
        "display.display(validation_targets.describe())"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "NqIbXxx222ea",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ## Entrenamiento de la red neuronal\n",
        "\n",
        "A continuaci\u00f3n, entrenaremos la red neuronal."
      ]
    },
    {
      "metadata": {
        "id": "6k3xYlSg27VB",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def construct_feature_columns(input_features):\n",
        "  \"\"\"Construct the TensorFlow Feature Columns.\n",
        "\n",
        "  Args:\n",
        "    input_features: The names of the numerical input features to use.\n",
        "  Returns:\n",
        "    A set of feature columns\n",
        "  \"\"\" \n",
        "  return set([tf.feature_column.numeric_column(my_feature)\n",
        "              for my_feature in input_features])"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "De9jwyy4wTUT",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):\n",
        "    \"\"\"Trains a neural network model.\n",
        "  \n",
        "    Args:\n",
        "      features: pandas DataFrame of features\n",
        "      targets: pandas DataFrame of targets\n",
        "      batch_size: Size of batches to be passed to the model\n",
        "      shuffle: True or False. Whether to shuffle the data.\n",
        "      num_epochs: Number of epochs for which data should be repeated. None = repeat indefinitely\n",
        "    Returns:\n",
        "      Tuple of (features, labels) for next data batch\n",
        "    \"\"\"\n",
        "    \n",
        "    # Convert pandas data into a dict of np arrays.\n",
        "    features = {key:np.array(value) for key,value in dict(features).items()}                                           \n",
        " \n",
        "    # Construct a dataset, and configure batching/repeating.\n",
        "    ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit\n",
        "    ds = ds.batch(batch_size).repeat(num_epochs)\n",
        "    \n",
        "    # Shuffle the data, if specified.\n",
        "    if shuffle:\n",
        "      ds = ds.shuffle(10000)\n",
        "    \n",
        "    # Return the next batch of data.\n",
        "    features, labels = ds.make_one_shot_iterator().get_next()\n",
        "    return features, labels"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "W-51R3yIKxk4",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def train_nn_regression_model(\n",
        "    my_optimizer,\n",
        "    steps,\n",
        "    batch_size,\n",
        "    hidden_units,\n",
        "    training_examples,\n",
        "    training_targets,\n",
        "    validation_examples,\n",
        "    validation_targets):\n",
        "  \"\"\"Trains a neural network regression model.\n",
        "  \n",
        "  In addition to training, this function also prints training progress information,\n",
        "  as well as a plot of the training and validation loss over time.\n",
        "  \n",
        "  Args:\n",
        "    my_optimizer: An instance of `tf.train.Optimizer`, the optimizer to use.\n",
        "    steps: A non-zero `int`, the total number of training steps. A training step\n",
        "      consists of a forward and backward pass using a single batch.\n",
        "    batch_size: A non-zero `int`, the batch size.\n",
        "    hidden_units: A `list` of int values, specifying the number of neurons in each layer.\n",
        "    training_examples: A `DataFrame` containing one or more columns from\n",
        "      `california_housing_dataframe` to use as input features for training.\n",
        "    training_targets: A `DataFrame` containing exactly one column from\n",
        "      `california_housing_dataframe` to use as target for training.\n",
        "    validation_examples: A `DataFrame` containing one or more columns from\n",
        "      `california_housing_dataframe` to use as input features for validation.\n",
        "    validation_targets: A `DataFrame` containing exactly one column from\n",
        "      `california_housing_dataframe` to use as target for validation.\n",
        "      \n",
        "  Returns:\n",
        "    A tuple `(estimator, training_losses, validation_losses)`:\n",
        "      estimator: the trained `DNNRegressor` object.\n",
        "      training_losses: a `list` containing the training loss values taken during training.\n",
        "      validation_losses: a `list` containing the validation loss values taken during training.\n",
        "  \"\"\"\n",
        "\n",
        "  periods = 10\n",
        "  steps_per_period = steps / periods\n",
        "  \n",
        "  # Create a DNNRegressor object.\n",
        "  my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)\n",
        "  dnn_regressor = tf.estimator.DNNRegressor(\n",
        "      feature_columns=construct_feature_columns(training_examples),\n",
        "      hidden_units=hidden_units,\n",
        "      optimizer=my_optimizer\n",
        "  )\n",
        "  \n",
        "  # Create input functions.\n",
        "  training_input_fn = lambda: my_input_fn(training_examples, \n",
        "                                          training_targets[\"median_house_value\"], \n",
        "                                          batch_size=batch_size)\n",
        "  predict_training_input_fn = lambda: my_input_fn(training_examples, \n",
        "                                                  training_targets[\"median_house_value\"], \n",
        "                                                  num_epochs=1, \n",
        "                                                  shuffle=False)\n",
        "  predict_validation_input_fn = lambda: my_input_fn(validation_examples, \n",
        "                                                    validation_targets[\"median_house_value\"], \n",
        "                                                    num_epochs=1, \n",
        "                                                    shuffle=False)\n",
        "\n",
        "  # Train the model, but do so inside a loop so that we can periodically assess\n",
        "  # loss metrics.\n",
        "  print(\"Training model...\")\n",
        "  print(\"RMSE (on training data):\")\n",
        "  training_rmse = []\n",
        "  validation_rmse = []\n",
        "  for period in range (0, periods):\n",
        "    # Train the model, starting from the prior state.\n",
        "    dnn_regressor.train(\n",
        "        input_fn=training_input_fn,\n",
        "        steps=steps_per_period\n",
        "    )\n",
        "    # Take a break and compute predictions.\n",
        "    training_predictions = dnn_regressor.predict(input_fn=predict_training_input_fn)\n",
        "    training_predictions = np.array([item['predictions'][0] for item in training_predictions])\n",
        "    \n",
        "    validation_predictions = dnn_regressor.predict(input_fn=predict_validation_input_fn)\n",
        "    validation_predictions = np.array([item['predictions'][0] for item in validation_predictions])\n",
        "    \n",
        "    # Compute training and validation loss.\n",
        "    training_root_mean_squared_error = math.sqrt(\n",
        "        metrics.mean_squared_error(training_predictions, training_targets))\n",
        "    validation_root_mean_squared_error = math.sqrt(\n",
        "        metrics.mean_squared_error(validation_predictions, validation_targets))\n",
        "    # Occasionally print the current loss.\n",
        "    print(\"  period %02d : %0.2f\" % (period, training_root_mean_squared_error))\n",
        "    # Add the loss metrics from this period to our list.\n",
        "    training_rmse.append(training_root_mean_squared_error)\n",
        "    validation_rmse.append(validation_root_mean_squared_error)\n",
        "  print(\"Model training finished.\")\n",
        "\n",
        "  # Output a graph of loss metrics over periods.\n",
        "  plt.ylabel(\"RMSE\")\n",
        "  plt.xlabel(\"Periods\")\n",
        "  plt.title(\"Root Mean Squared Error vs. Periods\")\n",
        "  plt.tight_layout()\n",
        "  plt.plot(training_rmse, label=\"training\")\n",
        "  plt.plot(validation_rmse, label=\"validation\")\n",
        "  plt.legend()\n",
        "\n",
        "  print(\"Final RMSE (on training data):   %0.2f\" % training_root_mean_squared_error)\n",
        "  print(\"Final RMSE (on validation data): %0.2f\" % validation_root_mean_squared_error)\n",
        "\n",
        "  return dnn_regressor, training_rmse, validation_rmse"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "KueReMZ9Kxk7",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0007),\n",
        "    steps=5000,\n",
        "    batch_size=70,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "flxmFt0KKxk9",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ## Ajuste lineal\n",
        "Una buena pr\u00e1ctica est\u00e1ndar puede ser normalizar las entradas para que est\u00e9n dentro del rango -1, 1. Esto ayuda al SGD a no bloquearse al realizar pasos que son demasiado grandes en una dimensi\u00f3n o demasiado peque\u00f1os en otra. Los apasionados de la optimizaci\u00f3n num\u00e9rica pueden observar aqu\u00ed una relaci\u00f3n con la idea de usar un precondicionador."
      ]
    },
    {
      "metadata": {
        "id": "Dws5rIQjKxk-",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def linear_scale(series):\n",
        "  min_val = series.min()\n",
        "  max_val = series.max()\n",
        "  scale = (max_val - min_val) / 2.0\n",
        "  return series.apply(lambda x:((x - min_val) / scale) - 1.0)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "MVmuHI76N2Sz",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Tarea\u00a01: Normalizar los atributos con ajuste lineal\n",
        "**Normaliza las entradas a la escala -1, 1.**\n",
        "**Dedica alrededor de 5\u00a0minutos a entrenar y evaluar los datos recientemente normalizados. \u00bfQu\u00e9 nivel de eficacia puedes tener?**\n",
        "Como regla general, las redes neuronales se entrenan mejor cuando los atributos de entrada est\u00e1n casi en la misma escala.\n",
        "Realiza una comprobaci\u00f3n de estado de tus datos normalizados. (\u00bfQu\u00e9 ocurrir\u00eda si olvidaras normalizar un atributo?)\n"
      ]
    },
    {
      "metadata": {
        "id": "yD948ZgAM6Cx",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def normalize_linear_scale(examples_dataframe):\n",
        "  \"\"\"Returns a version of the input `DataFrame` that has all its features normalized linearly.\"\"\"\n",
        "  #\n",
        "  # Your code here: normalize the inputs.\n",
        "  #\n",
        "  pass\n",
        "\n",
        "normalized_dataframe = normalize_linear_scale(preprocess_features(california_housing_dataframe))\n",
        "normalized_training_examples = normalized_dataframe.head(12000)\n",
        "normalized_validation_examples = normalized_dataframe.tail(5000)\n",
        "\n",
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0007),\n",
        "    steps=5000,\n",
        "    batch_size=70,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "jFfc3saSxg6t",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer una soluci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "Ax_IIQVRx4gr",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Dado que la normalizaci\u00f3n usa m\u00edn. y m\u00e1x., debemos asegurarnos de que esta se realice en todo el conjunto de datos a la vez.\n",
        "\n",
        "En este caso podemos hacerlo, porque todos nuestros datos est\u00e1n en un mismo DataFrame. Si tuvi\u00e9ramos varios conjuntos de datos, una buena pr\u00e1ctica ser\u00eda derivar los par\u00e1metros de normalizaci\u00f3n del conjunto de entrenamiento y aplicarlos de manera id\u00e9ntica al conjunto de prueba."
      ]
    },
    {
      "metadata": {
        "id": "D-bJBXrJx-U_",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def normalize_linear_scale(examples_dataframe):\n",
        "  \"\"\"Returns a version of the input `DataFrame` that has all its features normalized linearly.\"\"\"\n",
        "  processed_features = pd.DataFrame()\n",
        "  processed_features[\"latitude\"] = linear_scale(examples_dataframe[\"latitude\"])\n",
        "  processed_features[\"longitude\"] = linear_scale(examples_dataframe[\"longitude\"])\n",
        "  processed_features[\"housing_median_age\"] = linear_scale(examples_dataframe[\"housing_median_age\"])\n",
        "  processed_features[\"total_rooms\"] = linear_scale(examples_dataframe[\"total_rooms\"])\n",
        "  processed_features[\"total_bedrooms\"] = linear_scale(examples_dataframe[\"total_bedrooms\"])\n",
        "  processed_features[\"population\"] = linear_scale(examples_dataframe[\"population\"])\n",
        "  processed_features[\"households\"] = linear_scale(examples_dataframe[\"households\"])\n",
        "  processed_features[\"median_income\"] = linear_scale(examples_dataframe[\"median_income\"])\n",
        "  processed_features[\"rooms_per_person\"] = linear_scale(examples_dataframe[\"rooms_per_person\"])\n",
        "  return processed_features\n",
        "\n",
        "normalized_dataframe = normalize_linear_scale(preprocess_features(california_housing_dataframe))\n",
        "normalized_training_examples = normalized_dataframe.head(12000)\n",
        "normalized_validation_examples = normalized_dataframe.tail(5000)\n",
        "\n",
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.005),\n",
        "    steps=2000,\n",
        "    batch_size=50,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "MrwtdStNJ6ZQ",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Tarea\u00a02: Probar un optimizador diferente\n",
        "\n",
        "** Usa los optmizadores AdaGrad y Adam, y compara el rendimiento.**\n",
        "\n",
        "El optimizador AdaGrad es una alternativa. La idea clave de AdaGrad es que modifica la tasa de aprendizaje de forma adaptativa para cada coeficiente de un modelo, lo cual disminuye la tasa de aprendizaje efectiva de forma mon\u00f3tona. Esto funciona muy bien para los problemas convexos, pero no siempre resulta ideal para el entrenamiento de redes neuronales con problemas no convexos. Puedes usar AdaGrad al especificar `AdagradOptimizer` en lugar de `GradientDescentOptimizer`. Ten en cuenta que, con AdaGrad, es posible que debas usar una tasa de aprendizaje m\u00e1s alta.\n",
        "\n",
        "Para los problemas de optimizaci\u00f3n no convexos, en algunas ocasiones Adam es m\u00e1s eficaz que AdaGrad. Para usar Adam, invoca el m\u00e9todo `tf.train.AdamOptimizer`. Este m\u00e9todo toma varios hiperpar\u00e1metros opcionales como argumentos, pero nuestra soluci\u00f3n solo especifica uno de estos (`learning_rate`). En un entorno de producci\u00f3n, debes especificar y ajustar los hiperpar\u00e1metros opcionales con cuidado."
      ]
    },
    {
      "metadata": {
        "id": "61GSlDvF7-7q",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "#\n",
        "# YOUR CODE HERE: Retrain the network using Adagrad and then Adam.\n",
        "#"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "FSPZIiYgyh93",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer la soluci\u00f3n."
      ]
    },
    {
      "metadata": {
        "id": "X1QcIeiKyni4",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Primero, probemos AdaGrad."
      ]
    },
    {
      "metadata": {
        "id": "Ntn4jJxnypGZ",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "_, adagrad_training_losses, adagrad_validation_losses = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.5),\n",
        "    steps=500,\n",
        "    batch_size=100,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "5JUsCdRRyso3",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Ahora, probemos Adam."
      ]
    },
    {
      "metadata": {
        "id": "lZB8k0upyuY8",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "_, adam_training_losses, adam_validation_losses = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.AdamOptimizer(learning_rate=0.009),\n",
        "    steps=500,\n",
        "    batch_size=100,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "twYgC8FGyxm6",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Imprimamos un gr\u00e1fico de m\u00e9tricas de p\u00e9rdida en paralelo."
      ]
    },
    {
      "metadata": {
        "id": "8RHIUEfqyzW0",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "plt.ylabel(\"RMSE\")\n",
        "plt.xlabel(\"Periods\")\n",
        "plt.title(\"Root Mean Squared Error vs. Periods\")\n",
        "plt.plot(adagrad_training_losses, label='Adagrad training')\n",
        "plt.plot(adagrad_validation_losses, label='Adagrad validation')\n",
        "plt.plot(adam_training_losses, label='Adam training')\n",
        "plt.plot(adam_validation_losses, label='Adam validation')\n",
        "_ = plt.legend()"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "UySPl7CAQ28C",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Tarea\u00a03: Explorar m\u00e9todos de normalizaci\u00f3n alternativos\n",
        "\n",
        "**Prueba alternar las normalizaciones para distintos atributos a fin de mejorar a\u00fan m\u00e1s el rendimiento.**\n",
        "\n",
        "Si observas detenidamente las estad\u00edsticas de resumen de los datos transformados, es posible que observes que, al realizar un ajuste lineal en algunos atributos, estos quedan agrupados cerca de `-1`.\n",
        "\n",
        "Por ejemplo, muchos atributos tienen una mediana de alrededor de `-0.8`, en lugar de `0.0`."
      ]
    },
    {
      "metadata": {
        "id": "QWmm_6CGKxlH",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "_ = training_examples.hist(bins=20, figsize=(18, 12), xlabelsize=2)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "Xx9jgEMHKxlJ",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Es posible que obtengamos mejores resultados al elegir formas adicionales para transformar estos atributos.\n",
        "\n",
        "Por ejemplo, un ajuste logar\u00edtmico podr\u00eda ayudar a algunos atributos. O bien, el recorte de los valores extremos podr\u00eda hacer que el resto del ajuste sea m\u00e1s informativo."
      ]
    },
    {
      "metadata": {
        "id": "baKZa6MEKxlK",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def log_normalize(series):\n",
        "  return series.apply(lambda x:math.log(x+1.0))\n",
        "\n",
        "def clip(series, clip_to_min, clip_to_max):\n",
        "  return series.apply(lambda x:(\n",
        "    min(max(x, clip_to_min), clip_to_max)))\n",
        "\n",
        "def z_score_normalize(series):\n",
        "  mean = series.mean()\n",
        "  std_dv = series.std()\n",
        "  return series.apply(lambda x:(x - mean) / std_dv)\n",
        "\n",
        "def binary_threshold(series, threshold):\n",
        "  return series.apply(lambda x:(1 if x > threshold else 0))"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "-wCCq_ClKxlO",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " El bloque anterior contiene algunas funciones de normalizaci\u00f3n adicionales posibles. Prueba algunas de estas o agrega otras propias.\n",
        "\n",
        "Ten en cuenta que, si normalizas el objetivo, deber\u00e1s anular la normalizaci\u00f3n de las predicciones para que las m\u00e9tricas de p\u00e9rdida sean comparables."
      ]
    },
    {
      "metadata": {
        "id": "8ToG-mLfMO9P",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def normalize(examples_dataframe):\n",
        "  \"\"\"Returns a version of the input `DataFrame` that has all its features normalized.\"\"\"\n",
        "  #\n",
        "  # YOUR CODE HERE: Normalize the inputs.\n",
        "  #\n",
        "  pass\n",
        "\n",
        "normalized_dataframe = normalize(preprocess_features(california_housing_dataframe))\n",
        "normalized_training_examples = normalized_dataframe.head(12000)\n",
        "normalized_validation_examples = normalized_dataframe.tail(5000)\n",
        "\n",
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0007),\n",
        "    steps=5000,\n",
        "    batch_size=70,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "GhFtWjQRzD2l",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer una soluci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "OMoIsUMmzK9b",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Estas son solo algunas formas en las que podemos pensar acerca de los datos. Otras transformaciones podr\u00edan funcionar incluso mejor.\n",
        "\n",
        "Las funciones `households`, `median_income` y `total_bedrooms` aparecen todas distribuidas normalmente en un espacio logar\u00edtmico.\n",
        "\n",
        "Las funciones `latitude`, `longitude` y `housing_median_age` probablemente ser\u00edan mejores si solamente se ajustaran de forma lineal, como antes.\n",
        "\n",
        "Las funciones `population`, `totalRooms` y `rooms_per_person` tienen algunos valores at\u00edpicos extremos. Parecen ser demasiado extremos como para que la normalizaci\u00f3n logar\u00edtmica resulte \u00fatil. Por lo tanto, los recortaremos en su lugar."
      ]
    },
    {
      "metadata": {
        "id": "XDEYkPquzYCH",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def normalize(examples_dataframe):\n",
        "  \"\"\"Returns a version of the input `DataFrame` that has all its features normalized.\"\"\"\n",
        "  processed_features = pd.DataFrame()\n",
        "\n",
        "  processed_features[\"households\"] = log_normalize(examples_dataframe[\"households\"])\n",
        "  processed_features[\"median_income\"] = log_normalize(examples_dataframe[\"median_income\"])\n",
        "  processed_features[\"total_bedrooms\"] = log_normalize(examples_dataframe[\"total_bedrooms\"])\n",
        "  \n",
        "  processed_features[\"latitude\"] = linear_scale(examples_dataframe[\"latitude\"])\n",
        "  processed_features[\"longitude\"] = linear_scale(examples_dataframe[\"longitude\"])\n",
        "  processed_features[\"housing_median_age\"] = linear_scale(examples_dataframe[\"housing_median_age\"])\n",
        "\n",
        "  processed_features[\"population\"] = linear_scale(clip(examples_dataframe[\"population\"], 0, 5000))\n",
        "  processed_features[\"rooms_per_person\"] = linear_scale(clip(examples_dataframe[\"rooms_per_person\"], 0, 5))\n",
        "  processed_features[\"total_rooms\"] = linear_scale(clip(examples_dataframe[\"total_rooms\"], 0, 10000))\n",
        "\n",
        "  return processed_features\n",
        "\n",
        "normalized_dataframe = normalize(preprocess_features(california_housing_dataframe))\n",
        "normalized_training_examples = normalized_dataframe.head(12000)\n",
        "normalized_validation_examples = normalized_dataframe.tail(5000)\n",
        "\n",
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.15),\n",
        "    steps=1000,\n",
        "    batch_size=50,\n",
        "    hidden_units=[10, 10],\n",
        "    training_examples=normalized_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=normalized_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "b7atJTbzU9Ca",
        "colab_type": "text",
        "slideshow": {
          "slide_type": "slide"
        }
      },
      "cell_type": "markdown",
      "source": [
        " ## Desaf\u00edo opcional: Usar solo los atributos de latitud y longitud\n",
        "\n",
        "**Entrena un modelo de red neuronal que use solo latitud y longitud como atributos.**\n",
        "\n",
        "A los agentes de bienes ra\u00edces les gusta decir que la ubicaci\u00f3n es el \u00fanico atributo importante en el precio de la vivienda.\n",
        "Veamos si podemos confirmar esto al entrenar un modelo que use solo latitud y longitud como atributos.\n",
        "\n",
        "Esto funcionar\u00e1 bien \u00fanicamente si nuestra red neuronal puede aprender no linealidades complejas a partir de la latitud y la longitud.\n",
        "\n",
        "**NOTA:** Es posible que necesitemos una estructura de red que tenga m\u00e1s capas que las que eran \u00fatiles anteriormente en el ejercicio."
      ]
    },
    {
      "metadata": {
        "id": "T5McjahpamOc",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "#\n",
        "# YOUR CODE HERE: Train the network using only latitude and longitude\n",
        "#"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "P8BLQ7T71JWd",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " ### Soluci\u00f3n\n",
        "\n",
        "Haz clic m\u00e1s abajo para conocer una soluci\u00f3n posible."
      ]
    },
    {
      "metadata": {
        "id": "1hwaFCE71OPZ",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Una buena idea es mantener latitud y longitud normalizadas:"
      ]
    },
    {
      "metadata": {
        "id": "djKtt4mz1ZEc",
        "colab_type": "code",
        "colab": {
          "autoexec": {
            "startup": false,
            "wait_interval": 0
          }
        }
      },
      "source": [
        "def location_location_location(examples_dataframe):\n",
        "  \"\"\"Returns a version of the input `DataFrame` that keeps only the latitude and longitude.\"\"\"\n",
        "  processed_features = pd.DataFrame()\n",
        "  processed_features[\"latitude\"] = linear_scale(examples_dataframe[\"latitude\"])\n",
        "  processed_features[\"longitude\"] = linear_scale(examples_dataframe[\"longitude\"])\n",
        "  return processed_features\n",
        "\n",
        "lll_dataframe = location_location_location(preprocess_features(california_housing_dataframe))\n",
        "lll_training_examples = lll_dataframe.head(12000)\n",
        "lll_validation_examples = lll_dataframe.tail(5000)\n",
        "\n",
        "_ = train_nn_regression_model(\n",
        "    my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.05),\n",
        "    steps=500,\n",
        "    batch_size=50,\n",
        "    hidden_units=[10, 10, 5, 5, 5],\n",
        "    training_examples=lll_training_examples,\n",
        "    training_targets=training_targets,\n",
        "    validation_examples=lll_validation_examples,\n",
        "    validation_targets=validation_targets)"
      ],
      "cell_type": "code",
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "Dw2Mr9JZ1cRi",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        " Esto no es tan malo para solo dos funciones. De todos modos, los valores de la propiedad pueden variar en distancias cortas."
      ]
    }
  ]
}
